/**
 *
 */
package exsun.jt808.data.util.parse;

import java.nio.charset.StandardCharsets;

/**
 * @author Administrator
 */
public class HexStrUtil
{

    /**
     * 用于建立十六进制字符的输出的小写字符数组
     */
    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 用于建立十六进制字符的输出的大写字符数组
     */
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data byte[]
     * @return 十六进制char[]
     */
    public static String encodeHex(byte[] data)
    {
        return encodeHex(data, true);
    }

    /**
     * @param data
     * @param offset
     * @param len
     * @return
     */
    public static String encodeHex(byte[] data, int offset, int len)
    {
        return encodeHex(data, offset, len, true);
    }

    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data        byte[]
     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式
     * @return 十六进制char[]
     */
    public static String encodeHex(byte[] data, boolean toLowerCase)
    {
        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    /**
     * @param data
     * @param offset
     * @param len
     * @param toLowerCase
     * @return
     */
    public static String encodeHex(byte[] data, int offset, int len, boolean toLowerCase)
    {
        return encodeHex(data, offset, len, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    private static String encodeHex1(byte[] data, int offset, int len, boolean toLowerCase)
    {
        byte[] tmp = new byte[len];
        System.arraycopy(tmp, offset, data, 0, len);
        return "";
    }


    /**
     * 将字节数组转换为十六进制字符数组
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制char[]
     */
    protected static String encodeHex(byte[] data, char[] toDigits)
    {
        int l = data.length;
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++)
        {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return String.valueOf(out);
    }

    /**
     * @param data
     * @param offset
     * @param len
     * @param toDigits
     * @return
     */
    protected static String encodeHex(byte[] data, int offset, int len, char[] toDigits)
    {
        int l = len;
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++)
        {
            out[j++] = toDigits[(0xF0 & data[i + offset]) >>> 4];
            out[j++] = toDigits[0x0F & data[i + offset]];
        }
        return String.valueOf(out);
    }


    public static double bytes2Double(byte[] arr, int offset, int len)
    {
        long value = 0;
        for (int i = 0; i < len; i++)
        {
            value |= ((long) (arr[i + offset] & 0xff)) << (8 * i);
        }
        return Double.longBitsToDouble(value);
    }


    /**
     * 注意：当byte大于127后，会变成负值，需要转回正数
     * @param bs
     * @param offset
     * @param len
     * @return
     */
    public static int bytesToInt(byte[] bs, int offset, int len)
    {
        int a = 0;
        for (int i = len - 1; i >= 0; i--)
        {
            int tmp = bs[i + offset];
            if (tmp < 0) {
                tmp = bs[i + offset] & 0xFF;
            }
            a += tmp * Math.pow(255, len - i - 1);
        }
        return a;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data byte[]
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data)
    {
        return encodeHexStr(data, true);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data        byte[]
     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式
     * @return 十六进制String
     */
    public static String encodeHexStr(byte[] data, boolean toLowerCase)
    {
        return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param data     byte[]
     * @param toDigits 用于控制输出的char[]
     * @return 十六进制String
     */
    protected static String encodeHexStr(byte[] data, char[] toDigits)
    {
        return new String(encodeHex(data, toDigits));
    }

    /**
     * 将十六进制字符数组转换为字节数组
     *
     * @param
     * @return byte[]
     * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度，将抛出运行时异常
     */
    public static byte[] decodeHex(String hexStr)
    {
        byte[] data = hexStr.getBytes();
        int len = data.length;

        if ((len & 0x01) != 0)
        {
            throw new RuntimeException("Odd number of characters.");
        }

        byte[] out = new byte[len >> 1];

        // two characters form the hex value.
        for (int i = 0, j = 0; j < len; i++)
        {
            int f = toDigit(data[j], j) << 4;
            j++;
            f = f | toDigit(data[j], j);
            j++;
            out[i] = (byte) (f & 0xFF);
        }

        return out;
    }

    /**
     * 将十六进制字符转换成一个整数
     *
     * @param ch    十六进制char
     * @param index 十六进制字符在字符数组中的位置
     * @return 一个整数
     * @throws RuntimeException 当ch不是一个合法的十六进制字符时，抛出运行时异常
     */
    protected static int toDigit(byte ch, int index)
    {
        int digit = Character.digit(ch, 16);
        if (digit == -1)
        {
            throw new RuntimeException("Illegal hexadecimal character " + ch
                    + " at index " + index);
        }
        return digit;
    }


    public static double bytes2Double(byte[] arr)
    {
        long value = 0;
        for (int i = 0; i < 8; i++)
        {
            value |= ((long) (arr[i] & 0xff)) << (8 * i);
        }
        return Double.longBitsToDouble(value);
    }

    public static void main(String[] args)
    {

        byte[] b = new byte[]{2, 0, 0, -126};

        byte[] b1 = new byte[]{-115, -37, 6, -54, 62, -117};
        long l1 = Long.parseLong(bytesToHexStr(b1));

        //String s = Integer.toBinaryString(bytesToInt(b,0,4)  ) ;
        String s2 = byte2Binary(b, 0, 4);
        String s3 = byte2IntString(b, 0, 4);

        String srcStr = "qwer";
        String encodeStr = encodeHexStr(srcStr.getBytes());
        String decodeStr = new String(decodeHex(encodeStr));
        System.out.println("before encode:" + srcStr);
        System.out.println("after encode:" + encodeStr);
        System.out.println("convert:" + decodeStr);
    }

    public static int HexToInt(String str)
    {
        int k;
        int j = 0;
        int i = 0;
        for (k = 1; k <= str.length(); k++)
        {
            switch (str.toCharArray()[k - 1])
            {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    i = Integer.parseInt(String.valueOf(str.toCharArray()[k - 1]));
                    // i = int.Parse(Str[k - 1]);
                    break;
                case 'A':
                    i = 10;
                    break;
                case 'B':
                    i = 11;
                    break;
                case 'C':
                    i = 12;
                    break;
                case 'D':
                    i = 13;
                    break;
                case 'E':
                    i = 14;
                    break;
                case 'F':
                    i = 15;
                    break;
                case 'a':
                    i = 10;
                    break;
                case 'b':
                    i = 11;
                    break;
                case 'c':
                    i = 12;
                    break;
                case 'd':
                    i = 13;
                    break;
                case 'e':
                    i = 14;
                    break;
                case 'f':
                    i = 15;
                    break;

            }
            j = j * 16 + i;
        }
        return j;
    }

    public static String byteArrToBinStr(byte[] bytes, int offset, int len)
    {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++)
        {
            sb.append(Integer.toBinaryString((bytes[offset + i] & 0xFF) + 0X100).substring(1));
        }
        return sb.toString();
    }

    public static String byte2Binary(byte[] bytes, int offset, int len)
    {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++)
        {
            sb.append(Integer.toBinaryString((bytes[offset + i] & 0xFF) + 0X100).substring(1));
        }
        return sb.toString();
    }

    /**
     * byte数组转hex

     * @return
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(
                        s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, StandardCharsets.UTF_8);
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }

    /**
     * hex转byte数组
     *
     * @param hex
     * @return
     */
    public static byte[] hexToBytes(String hex)
    {
        int m = 0, n = 0;
        int byteLen = hex.length() / 2; // 每两个字符描述一个字节
        byte[] ret = new byte[byteLen];
        for (int i = 0; i < byteLen; i++)
        {
            m = i * 2 + 1;
            n = m + 1;
            int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n));
            ret[i] = Byte.valueOf((byte) intVal);
        }
        return ret;
    }

    /**
     * byte数组转hex
     *
     * @param bytes
     * @return
     */
    public static String bytesToHexStr(byte[] bytes)
    {
//        long num = 0;
//        for (int ix = 0; ix < 6; ++ix) {
//            num <<= 8;
//            num |= (bytes[ix] & 0xff);
//        }
//        return num;
        String strHex = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < bytes.length; n++)
        {
            strHex = Integer.toHexString(bytes[n] & 0xFF);
            // 每个字节由两个字符表示，位数不够，高位补0
            sb.append((strHex.length() == 1) ? "0" + strHex : strHex);
        }
        return sb.toString().trim();
    }


    public static String bytesToLong(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++)
        {
            sb.append(i & 0xFF);
        }
        return sb.toString();
    }

    /**
     * 16进制 字符串转化为2进制字符串
     *
     * @param hexString 16进制字符串
     * @return 2进制字符串
     */
    public static String hexString2Binary(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0) {
            return null;
        }
        StringBuilder bString = new StringBuilder();
        String tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));
            bString.append(tmp.substring(tmp.length() - 4));
        }
        return bString.toString();
    }

    /**
     * byte[]转换为10进制
     *
     * @param bytes
     * @param offset
     * @param len
     * @return
     */
    public static String byte2IntString(byte[] bytes, int offset, int len)
    {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++)
        {
            sb.append(Integer.valueOf(bytes[i + offset] + ""));
        }
        return sb.toString();
    }
}
